# coding:utf-8

from fastapi import FastAPI, Path, Query
import uvicorn
from pydantic import BaseModel
import sys
import os
import time
import io
import contextlib
from langchain_experimental.tools.python.tool import PythonREPL
import ast
from RestrictedPython import safe_builtins

from logger import logger
from core.type.BaseAPIClass import BaseItem
from core.process.DataAnalysisClass import DataAnalysisClass

app = FastAPI()

# class Item(BaseModel):
#     name:str
#     price:float
#     is_offer:bool=None

# 定义安全的全局变量
safe_globals = {
    '__builtins__': {
        'print': print,
        'range': range,
        'int': int,
        'str': str,
        'list': list,
        # 仅允许安全的函数/类型
    }
}


def run_code_with_params(code_template: str, params: dict):
    # 重定向输出
    old_stdout = sys.stdout
    sys.stdout = buffer = io.StringIO()

    try:
        # 动态生成代码
        code = code_template.format(**params)
        
        # 创建 PythonREPL 实例
        python_repl = PythonREPL(globals=safe_globals)
        
        # 执行代码
        output = python_repl.run(code)
        # output = buffer.getvalue()
        logger.info(f"捕获到的输出: {str(output)}")

        return output
    except Exception as e:
        raise Exception(f"run_code_with_params Error: {str(e)}, Time:{int(time.time())}")
    finally:
        sys.stdout = old_stdout  # 恢复标准输出

def safe_format_code(code_template: str, params: dict):
    # 检查参数值是否为简单类型（数字、字符串等）
    for key, value in params.items():
        if not isinstance(value, (int, float, str)):
            raise ValueError(f"参数 {key} 的值类型不安全: {type(value)}")
    
    # 使用 ast 检查代码模板是否合法
    try:
        ast.parse(code_template)
    except SyntaxError:
        raise ValueError("代码模板语法错误")
    
    # 格式化代码
    return code_template.format(**params)

@app.get("/live")
async def live():
    try:
        ip = "0.0.0.0"
        response_data = {"timestamp":int(time.time()), "code":"SUCCESS", "message":"null", "data":{"name":"dify-tool","ip":f"{ip}"}}
        logger.info(response_data)
        return response_data
    except Exception as e:
        raise Exception(f"Http Error: {str(e)}, Time:{int(time.time())}")

@app.get("/ready")
async def ready():
    try:
        ip = "0.0.0.0"
        response_data = {"timestamp":int(time.time()), "code":"SUCCESS", "message":"null", "data":{"name":"dify-tool","ip":f"{ip}"}}
        logger.info(response_data)
        return response_data
    except Exception as e:
        raise Exception(f"Http Error: {str(e)}, Time:{int(time.time())}")
    
@app.get("/api/probe")
async def probe():
    try:
        ip = "0.0.0.0"
        response_data = {"timestamp":int(time.time()), "code":"SUCCESS", "message":"null", "data":{"name":"dify-tool","ip":f"{ip}"}}
        logger.info(response_data)
        return response_data
    except Exception as e:
        raise Exception(f"Http Error: {str(e)}, Time:{int(time.time())}")
    
@app.get("/api/test")
async def test():
    # 展示当前目录的文件层次
    file_tree = os.popen('tree').read()
    logger.info(file_tree)
    return f'<pre>Hello, Docker!\n\nFile Tree:\n{file_tree}</pre>'

@app.post("/api/read/")
async def read_data(item: BaseItem):
    try:
        logger.info(item)
        
        df = item.read_data()

        # 创建一个 StringIO 对象
        output_buffer = io.StringIO()

        with contextlib.redirect_stdout(output_buffer):
            if df.shape[0] > 0:
                # 输出字段类型
                print("数据信息：")
                print(df.info())

                # 输出前五行数据
                print("\n前五行数据：")
                print(df.head())

        # 获取 StringIO 中的内容
        output = output_buffer.getvalue()
        output_buffer.close() # 关闭 StringIO 对象

        return output
    except Exception as e:
        raise Exception(f"read_data Error: {str(e)}, Time:{int(time.time())}")
    
@app.post("/api/quick_describe/")
async def quick_describe(item: BaseItem):
    try:
        logger.info(item)
        
        df = item.read_data()
        dataAnalysisClass = DataAnalysisClass()
        dataAnalysisClass.data = df
        output = dataAnalysisClass.quick_describe()

        return output
    except Exception as e:
        raise Exception(f"quick_describe Error: {str(e)}, Time:{int(time.time())}")

@app.post("/api/code_executor/")
async def code_executor(item: BaseItem):
    try:
        logger.info(item)

        code_str = """
import pandas as pd

data_path = '{data_path}'

df = pd.read_excel(data_path)

{code_str}

# 将DataFrame转换为CSV格式的字符串
csv_string = df.to_csv(index=False)

# 打印CSV格式的字符串
print(csv_string)

try:
    from tabulate import tabulate
    print(tabulate(df.head(), headers='keys', tablefmt='pipe', showindex=False))
except ImportError:
    print(df.head().to_string())
# 备选方案:使用DataFrame的to_string()方法


        """

        df = item.read_data()
        df.to_excel("./data/tmp/tmp.xlsx", index=False)

        params = {'data_path':'./data/tmp/tmp.xlsx', 'code_str': item.code_str}
        output = run_code_with_params(code_template=code_str, params=params)
        
        print("执行结果:", output) 
        return output

    except Exception as e:
        raise Exception(f"code_executor Error: {str(e)}, Time:{int(time.time())}")

def test():
    code_template = """
a = {a}
b = {b}
result = a * b
print(result)
    """
    params = {'a': 5, 'b': 6}
    safe_code = safe_format_code(code_template=code_template, params=params)
    output = run_code_with_params(safe_code, params)
    print("执行结果:", output)  # 输出: 执行结果: 30

if __name__ == "__main__":
    uvicorn.run(app, host="0.0.0.0", port=5000, reload=False)
    # test()